home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 4 / ETO Development Tools 4.iso / Tools - Objects / MacApp / MacApp 3.0a2 / Libraries / UMenuMgr.cp < prev    next >
Encoding:
Text File  |  1991-05-01  |  27.6 KB  |  1,142 lines  |  [TEXT/MPS ]

  1. // UMenuMgr.cp 
  2. // Copyright © 1984-1991 by Apple Computer Inc. All rights reserved.
  3.  
  4. #ifndef __UMENUMGR__
  5. #include <UMenuMgr.h>
  6. #endif
  7.  
  8. #ifndef __STDIO__
  9. #include <StdIo.h>
  10. #endif
  11.  
  12. #ifndef __GEOMETRY__
  13. #include <Geometry.h>
  14. #endif
  15.  
  16. #ifndef __MEMORY__
  17. #include <Memory.h>
  18. #endif
  19.  
  20. #ifndef __UOBJECT__
  21. #include <UObject.h>
  22. #endif
  23.  
  24. #ifndef __UFAILURE__
  25. #include <UFailure.h>
  26. #endif
  27.  
  28. #ifndef __ULIST__
  29. #include <UList.h>
  30. #endif
  31.  
  32. #ifndef __UPATCH__
  33. #include <UPatch.h>
  34. #endif
  35.  
  36. #ifndef __UMEMORY__
  37. #include <UMemory.h>
  38. #endif
  39.  
  40. #ifndef __TEXTEDIT__
  41. #include <Textedit.h>
  42. #endif
  43.  
  44. #ifndef __OSUTILS__
  45. #include <OSUtils.h>
  46. #endif
  47.  
  48. #ifndef __UMACAPPUTILITIES__
  49. #include <UMacAppUtilities.h>
  50. #endif
  51.  
  52. #ifndef __UMACAPPGLOBALS__
  53. #include <UMacAppGlobals.h>
  54. #endif
  55.  
  56. #ifndef __TRAPS__
  57. #include <Traps.h>
  58. #endif
  59.  
  60. #ifndef __TOOLUTILS__
  61. #include <ToolUtils.h>
  62. #endif
  63.  
  64. #ifndef __RESOURCES__
  65. #include <Resources.h>
  66. #endif
  67.  
  68. #ifndef __UITERATOR__
  69. #include <UIterator.h>
  70. #endif
  71.  
  72. #define    kHierarchical        TRUE
  73. #define    kNotHierarchical    !kHierarchical
  74.  
  75. #define    kDoHierarchical     TRUE
  76. #define    kDontDoHierarchical !kDoHierarchical
  77.  
  78. typedef struct MenuCmdRecord
  79. {
  80.     CmdNumber theCmdNumber;
  81.     short theMenuNumber;
  82.     short theItemNumber;
  83. }    *MenuCmdRecordPtr, ** MenuCmdRecordHandle;
  84.  
  85. class TCmdTable : public TSortedDynamicArray
  86. {
  87. public:
  88.     virtual pascal void ICmdTable(void);
  89.     virtual pascal CompareResult CompareElements(void* Element1,
  90.                                                  void* Element2);// override 
  91.     virtual pascal void CmdToMenuItem(CmdNumber theCommand,
  92.                                       short& menu,
  93.                                       short& item);
  94.     virtual pascal CmdNumber CmdFromMenuItem(short menu,
  95.                                              short item);
  96.     /* Given a menuID,item # return the appropriate command number. if there
  97.       is no such command number, return -BOR(((menu) << 8), item).  If the
  98.       item number is <0 then assume that it is a negative command number. */
  99.     virtual pascal void AddToTable(CmdNumber commandNumber,
  100.                                    short menuNumber,
  101.                                    short itemNumber);
  102. };
  103.  
  104.  
  105. class TMenuTable : public THandleList
  106. {
  107. public:
  108.     virtual pascal void IMenuTable(void);
  109.     virtual pascal MenuHandle GetMenu(short menuID);
  110.     virtual pascal CompareResult Compare(Handle item1,
  111.                                          Handle item2);// override 
  112. };
  113.  
  114.  
  115. Handle pHNullMenuProc;                            // Handle to null menu proc 
  116.  
  117. TCmdTable* gCmdTable;                            /* command numbers and their associated menu
  118.                                                   and item numbers */
  119. TMenuTable* gMenuTable;                            // list of menus created/managed by MacApp 
  120.  
  121. pascal void NullMenuProc(short message,
  122.                          MenuHandle aMenuHandle,
  123.                          Rect& menuRect,
  124.                          Point hitPt,
  125.                          short& whichItem);
  126.  
  127. //--------------------------------------------------------------------------------------------------
  128. Boolean gMenusAreInvalid;
  129. Boolean gMenuBarIsInvalid;
  130.  
  131. #if qDebug
  132. Boolean gTraceSetupMenus;
  133. #endif
  134.  
  135. //--------------------------------------------------------------------------------------------------
  136. #pragma segment MAInit
  137.  
  138. pascal void TCmdTable::ICmdTable(void)
  139.  
  140. {
  141.     this->ISortedDynamicArray(0, sizeof(MenuCmdRecord));
  142. }
  143.  
  144. //--------------------------------------------------------------------------------------------------
  145. #pragma segment MAMenuRes
  146.  
  147. pascal CompareResult TCmdTable::CompareElements(void* Element1,
  148.                                                 void* Element2)// override 
  149.  
  150. {
  151.     CmdNumber theCommanditem1 = ((MenuCmdRecordPtr)Element1)->theCmdNumber;
  152.     CmdNumber theCommanditem2 = ((MenuCmdRecordPtr)Element2)->theCmdNumber;
  153.  
  154.     if (theCommanditem1 > theCommanditem2)
  155.         return kItem1GreaterThanItem2;
  156.     else if (theCommanditem1 < theCommanditem2)
  157.         return kItem1LessThanItem2;
  158.     else
  159.         return kItem1EqualItem2;
  160. }
  161.  
  162. //--------------------------------------------------------------------------------------------------
  163. #pragma segment MAMenuRes
  164.  
  165. // A local class to pass in to the search routine as a comparison function
  166. class CCmdToMenuItem
  167. {
  168.     // Fields
  169.  
  170.     CmdNumber& theCommand;
  171.     TCmdTable* theCmdTable;
  172.  
  173. public:
  174.  
  175.     // Constructor
  176.  
  177.     CCmdToMenuItem(CmdNumber& aCommand,
  178.                    TCmdTable* aCmdTable) :
  179.         theCommand(aCommand),
  180.         theCmdTable(aCmdTable)
  181.     {
  182.     }
  183.  
  184.     // Method
  185.  
  186.     pascal CompareResult TestItem(ArrayIndex anItem);
  187. };
  188.  
  189. #pragma segment MAMenuRes
  190. pascal CompareResult CCmdToMenuItem::TestItem(ArrayIndex anItem)
  191. {
  192.     CmdNumber theCommanditem;
  193.  
  194.     theCommanditem = ((MenuCmdRecordPtr)theCmdTable->ComputeAddress(anItem))->theCmdNumber;
  195.  
  196.     if (theCommanditem > theCommand)
  197.         return kItemGreaterThanCriteria;
  198.     else if (theCommanditem < theCommand)
  199.         return kItemLessThanCriteria;
  200.     else
  201.         return kItemEqualCriteria;
  202. }
  203.  
  204. typedef pascal CompareResult(* TestItem)(ArrayIndex anItem,
  205.                                          void* staticLink);
  206.  
  207. #pragma segment MAMenuRes
  208. pascal void TCmdTable::CmdToMenuItem(CmdNumber theCommand,
  209.                                      short& menu,
  210.                                      short& item)
  211.  
  212. {
  213.     ArrayIndex index = 0;
  214.     CCmdToMenuItem aCCmdToMenuItem(theCommand, this);
  215.  
  216.     if (theCommand < 0)                            /* negative commands are mapped not table
  217.                                                   based */
  218.     {
  219.         menu = (short)((-theCommand) >> 8);
  220.         item = (short)((-theCommand) & 255);
  221.     }
  222.     else
  223.     {
  224.         if (this->DoSearchElement((TestItem) & CCmdToMenuItem::TestItem, &aCCmdToMenuItem, index))
  225.         {
  226.             MenuCmdRecordPtr aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
  227.             menu = aMenuCmdRecordPtr->theMenuNumber;
  228.             item = aMenuCmdRecordPtr->theItemNumber;
  229.         }
  230.         else                                    // not found 
  231.             {
  232.             menu = 0;
  233.             item = 0;
  234.         }
  235.     }
  236. }
  237.  
  238. //--------------------------------------------------------------------------------------------------
  239. #pragma segment MAMenuRes
  240.  
  241. pascal CmdNumber TCmdTable::CmdFromMenuItem(short menu,
  242.                                             short item)
  243. /* Given a menuID/item # return the appropriate command number. if there
  244.   is no such command number, return -BOR(((menu) << 8), item).  If the
  245.   item number is <0 then assume that it is a negative command number. */
  246.  
  247. {
  248.     if (item < 0)
  249.         return -item;
  250.     else
  251.     {
  252.         if (item > 0)
  253.         {
  254.  
  255.             // Search the table linearly. 
  256.             for (ArrayIndex i = 1; i <= this->GetSize(); ++i)
  257.             {
  258.                 MenuCmdRecordPtr aMenuCmdRecordPtr = (MenuCmdRecordPtr)this->ComputeAddress(i);
  259.                 if ((menu == aMenuCmdRecordPtr->theMenuNumber) && (item == aMenuCmdRecordPtr->theItemNumber))
  260.                 {
  261.                     return aMenuCmdRecordPtr->theCmdNumber;
  262.                 }
  263.             }
  264.         }
  265.  
  266. #if qDebugMsg
  267.         if ((menu > 127) || (item > 255))
  268.         {
  269.             fprintf(stderr, "menu : %1d , item : %1d \n", menu, item);
  270.             fprintf(stderr, "Menu/item number is too big for a negative command number!");
  271.             ProgramBreak("Try using a negative item number instead.");
  272.         }
  273. #endif
  274.  
  275.         return -((menu << 8) | item);
  276.     }
  277. }
  278.  
  279. //--------------------------------------------------------------------------------------------------
  280. #pragma segment MAInit
  281.  
  282. pascal void TCmdTable::AddToTable(CmdNumber commandNumber,
  283.                                   short menuNumber,
  284.                                   short itemNumber)
  285.  
  286. {
  287.     MenuCmdRecord arec;
  288.  
  289.  
  290.     if (commandNumber > 0)                        // Negative numbers are mapped not tabled 
  291.     {
  292.         arec.theCmdNumber = commandNumber;
  293.         arec.theMenuNumber = menuNumber;
  294.         arec.theItemNumber = itemNumber;
  295.  
  296.         this->InsertElementInOrder((Ptr) & arec);
  297.     }
  298. }
  299.  
  300. //--------------------------------------------------------------------------------------------------
  301. #pragma segment MAInit
  302.  
  303. pascal void TMenuTable::IMenuTable(void)
  304.  
  305. {
  306.     this->IHandleList();
  307. }
  308.  
  309. //--------------------------------------------------------------------------------------------------
  310. #pragma segment MAMenuRes
  311.  
  312. // A local class to pass in to the search routine as a comparison function
  313. class CGetMenu
  314. {
  315.     // Fields
  316.  
  317.     short& menuID;
  318.  
  319. public:
  320.  
  321.     // Constructor
  322.  
  323.     CGetMenu(short& amenuID) :
  324.         menuID(amenuID)
  325.     {
  326.     }
  327.  
  328.     // Method
  329.  
  330.     pascal CompareResult TestItem(Handle anItem);
  331. };
  332.  
  333. #pragma segment MAMenuRes
  334. pascal CompareResult CGetMenu::TestItem(Handle anItem)
  335. {
  336.     short menuIDitem = (*((MenuHandle)anItem))->menuID;
  337.  
  338.     if (menuIDitem > menuID)
  339.         return kItemGreaterThanCriteria;
  340.     else if (menuIDitem < menuID)
  341.         return kItemLessThanCriteria;
  342.     else
  343.         return kItemEqualCriteria;
  344. }
  345.  
  346.  
  347. typedef pascal CompareResult(* GetMenuTestItem)(Handle anItem,
  348.                                                 void* staticLink);
  349.  
  350. #pragma segment MAMenuRes
  351. pascal MenuHandle TMenuTable::GetMenu(short menuID)
  352.  
  353. {
  354.     ArrayIndex index;
  355.     CGetMenu aCGetMenu(menuID);
  356.  
  357.     return ((MenuHandle)this->DoSearch((GetMenuTestItem) & CGetMenu::TestItem, &aCGetMenu, index));    // discard index 
  358. }
  359.  
  360. //--------------------------------------------------------------------------------------------------
  361. #pragma segment MAMenuRes
  362.  
  363. pascal CompareResult TMenuTable::Compare(Handle item1,
  364.                                          Handle item2)// override 
  365.  
  366. {
  367.     short menuID1 = (*((MenuHandle)item1))->menuID;
  368.     short menuID2 = (*((MenuHandle)item2))->menuID;
  369.  
  370.     if (menuID1 > menuID2)
  371.         return kItem1GreaterThanItem2;
  372.     else if (menuID1 < menuID2)
  373.         return kItem1LessThanItem2;
  374.     else
  375.         return kItem1EqualItem2;
  376. }
  377.  
  378. //--------------------------------------------------------------------------------------------------
  379. #if qDebugMsg
  380. #pragma segment MADebug
  381.  
  382. char TraceMenuName(CmdNumber aCmd)
  383. // For debugging purposes only--used to dump the name and number of a command 
  384.  
  385. {
  386.     Str255 cmdName;
  387.  
  388.     CmdToName(aCmd, cmdName);
  389.     fprintf(stderr, " %1d [%s],", aCmd, (char *) cmdName);
  390.     return ' ';
  391. }
  392. #endif
  393.  
  394. //--------------------------------------------------------------------------------------------------
  395. #pragma segment MAMenuRes
  396.  
  397. pascal void InvalidateMenus(void)
  398.  
  399. {
  400.     gMenusAreInvalid = TRUE;
  401. }
  402.  
  403. //--------------------------------------------------------------------------------------------------
  404. #pragma segment MAMenuRes
  405.  
  406. struct MenuBarRecord
  407. {
  408.     short nMenus;
  409.     short menuID[1000];
  410. };
  411.  
  412.  
  413. typedef MenuBarRecord* MenuBarPtr, ** MenuBarHandle;
  414.  
  415. pascal void AddMenuBar(short itsID,
  416.                        Boolean isHierarchical)
  417.  
  418. {
  419.     short hier;
  420.     MenuBarHandle hmbar;
  421.  
  422.  
  423.     if (isHierarchical)
  424.         hier = -1;
  425.     else
  426.         hier = 0;
  427.  
  428.     hmbar = (MenuBarHandle)GetResource('MBAR', itsID);
  429.     if (hmbar)
  430.     {
  431.         for (short i = 0; i <= (*hmbar)->nMenus; ++i)
  432.         {
  433.             MenuHandle aMenu = MAGetMenu((*hmbar)->menuID[i]);
  434.             if (aMenu)
  435.                 MAInsertMenu(aMenu, hier);
  436.         }
  437.         ReleaseResource((Handle)hmbar);
  438.         // hmbar = NULL;
  439.     }
  440. }
  441.  
  442. //--------------------------------------------------------------------------------------------------
  443. #pragma segment MAMenuRes
  444.  
  445. pascal void ValidateMenus(void)
  446.  
  447. {
  448.     gMenusAreInvalid = FALSE;
  449. }
  450.  
  451. //--------------------------------------------------------------------------------------------------
  452. #pragma segment MAMenuRes
  453.  
  454. pascal Boolean MenusHavePendingUpdate(void)
  455.  
  456. {
  457.     return gMenusAreInvalid;
  458. }
  459.  
  460. //--------------------------------------------------------------------------------------------------
  461. #pragma segment MAMenuRes
  462.  
  463. pascal void InvalidateMenuBar(void)
  464. {
  465.     InvalidateMenus();                            /* if the menubar is invalidated then the
  466.                                                   menu items must be also */
  467.  
  468.     /* On systems that have invalidate menu bar use that functionality instead of setting the global.
  469.       The system will redraw the menu bar at the next convenient time. */
  470.     if (TrapExists(_InvalMenuBar))
  471.     {
  472.         InvalMenuBar();
  473.         gMenuBarIsInvalid = FALSE;                /* don't track in the application when using
  474.                                                   the trap */
  475.     }
  476.     else
  477.         gMenuBarIsInvalid = TRUE;
  478. }
  479.  
  480. //--------------------------------------------------------------------------------------------------
  481. #pragma segment MAMenuRes
  482.  
  483. pascal void ValidateMenuBar(void)
  484.  
  485. {
  486.     gMenuBarIsInvalid = FALSE;
  487. }
  488.  
  489. //--------------------------------------------------------------------------------------------------
  490. #pragma segment MAMenuRes
  491.  
  492. pascal Boolean MenuBarHasPendingUpdate()
  493.  
  494. {
  495.     return gMenuBarIsInvalid;
  496. }
  497.  
  498. //--------------------------------------------------------------------------------------------------
  499. #pragma segment MAMenuRes
  500.  
  501. pascal Boolean CmdEnabled(CmdNumber cmd)
  502.  
  503. {
  504.     short menuNo;
  505.     short itemNo;
  506.     MenuHandle theMenu;
  507.  
  508.     theMenu = CmdToComponents(cmd, menuNo, itemNo);
  509.  
  510.     if (theMenu)
  511.         if ((itemNo > 0) && (itemNo < 32))
  512.             return (((*theMenu)->enableFlags >> itemNo) != 0);
  513.         else
  514.             return TRUE;
  515.     else
  516.         return FALSE;
  517. }
  518.  
  519. //--------------------------------------------------------------------------------------------------
  520. #pragma segment MAMenuRes
  521.  
  522. pascal CmdNumber CmdFromMenuItem(short menu,
  523.                                  short item)
  524.  
  525. {
  526.     return gCmdTable->CmdFromMenuItem(menu, item);
  527. }
  528.  
  529. //--------------------------------------------------------------------------------------------------
  530. #pragma segment MAMenuRes
  531.  
  532. pascal void CmdToMenuItem(CmdNumber aCmd,
  533.                           short& menu,
  534.                           short& item)
  535.  
  536. {
  537.     gCmdTable->CmdToMenuItem(aCmd, menu, item);
  538. }
  539.  
  540. //--------------------------------------------------------------------------------------------------
  541. #pragma segment MAMenuRes
  542.  
  543. pascal void CmdToName(CmdNumber aCmd,
  544.                       Str255& menuText)
  545.  
  546. {
  547.     short anItem;
  548.     short aMenu;
  549.  
  550.     menuText = "";
  551.  
  552.     MenuHandle mHandle = CmdToComponents(aCmd, aMenu, anItem);
  553.     if (mHandle)
  554.         GetItem(mHandle, anItem, menuText);
  555. }
  556.  
  557. //--------------------------------------------------------------------------------------------------
  558. #pragma segment MAMenuRes
  559.  
  560. pascal MenuHandle CmdToComponents(CmdNumber cmd,
  561.                                   short& menuNo,
  562.                                   short& itemNo)
  563.  
  564. {
  565.     CmdToMenuItem(cmd, menuNo, itemNo);
  566.     if (menuNo)                                    // was found 
  567.         return MAGetMenu(menuNo);
  568.     else
  569.         return NULL;
  570. }
  571.  
  572. //--------------------------------------------------------------------------------------------------
  573. #pragma segment MAMenuRes
  574.  
  575. #pragma segment MAMenuRes
  576.  
  577. // Calls DoToMenu for each menu in the menu bar, DoToMenu needs to be smart enough to
  578. // exclude hierarchical if desired.
  579. pascal void EachMenuDo(DoToMenuType DoToMenu,
  580.                               void* staticLink)
  581. {
  582.     CHandleIterator iter(gMenuTable);
  583.     
  584.     for (MenuHandle item = (MenuHandle)iter.FirstHandle(); iter.More(); item = (MenuHandle)iter.NextHandle())
  585.         if (GetMHandle((*(item))->menuID))                    // if it's in the menulist
  586.             DoToMenu(item, kHierarchical, staticLink);
  587. }
  588.  
  589. //--------------------------------------------------------------------------------------------------
  590. #pragma segment MAMenuRes
  591.  
  592. pascal void Enable(CmdNumber aCmd,
  593.                    Boolean canDo)
  594.  
  595. {
  596.     short menu;
  597.     short item;
  598.     MenuHandle aMenuHandle;
  599.  
  600. #if qDebugMsg
  601.     if (gTraceSetupMenus)
  602.         fprintf(stderr, "..... Enable(%c%s)", TraceMenuName(aCmd), gBoolString[canDo]);
  603. #endif
  604.  
  605.     aMenuHandle = CmdToComponents(aCmd, menu, item);
  606.     if (aMenuHandle)
  607.         if (canDo)
  608.             EnableItem(aMenuHandle, item);
  609.         else
  610.             DisableItem(aMenuHandle, item);
  611. }
  612.  
  613. //--------------------------------------------------------------------------------------------------
  614. #pragma segment MAMenuRes
  615.  
  616. pascal void EnableCheck(CmdNumber aCmd,
  617.                         Boolean canDo,
  618.                         Boolean checkIt)
  619.  
  620. {
  621.     short menu;
  622.     short item;
  623.     MenuHandle aMenuHandle;
  624.  
  625. #if qDebugMsg
  626.     if (gTraceSetupMenus)
  627.         fprintf(stderr, "..... EnableCheck(%c%s, %s)", TraceMenuName(aCmd), gBoolString[canDo], gBoolString[checkIt]);
  628. #endif
  629.  
  630.     aMenuHandle = CmdToComponents(aCmd, menu, item);
  631.     if (aMenuHandle)
  632.     {
  633.         if (canDo)
  634.             EnableItem(aMenuHandle, item);
  635.         else
  636.             DisableItem(aMenuHandle, item);
  637.         CheckItem(aMenuHandle, item, checkIt);
  638.     }
  639. }
  640.  
  641. //--------------------------------------------------------------------------------------------------
  642. #pragma segment MAMenuRes
  643.  
  644. pascal void DoGetResMenu(void* staticLink)
  645.  
  646. {
  647.     short menuResID = *((short*)staticLink);
  648.     *((MenuHandle *)staticLink) = (MenuHandle)GetResource('MENU', menuResID);
  649. }
  650.  
  651.  
  652. pascal MenuHandle GetResMenu(short menuResID)
  653. /* Allow us to get a menu when it's not available via GetMHandle.
  654.   !!! Really should perform the other functions of GetMenu (load menuproc, color table, etc.*/
  655.  
  656. {
  657.     long staticLink = menuResID;                // on entry to DoGetResMenu, staticLink is menuResID
  658.  
  659.     WithApplicationResFileDo(&DoGetResMenu, &staticLink);
  660.  
  661.     return (MenuHandle)staticLink;                // on exit from DoGetResMenu, staticLink is MenuHandle
  662. }
  663.  
  664. //--------------------------------------------------------------------------------------------------
  665. #pragma segment TRes
  666.  
  667. pascal MenuHandle ConvertToMenu(Handle CMNUHandle)
  668.  
  669. {
  670.     typedef CmdNumber* CmdNumberPtr;
  671.  
  672.     MenuHandle theMenuHandle = NULL;
  673.     Ptr theCMNUPtr;
  674.     Ptr theMENUPtr;
  675.     short i;
  676.     short menuNo;
  677.     short itemNo;
  678.     CmdNumber cmdNo;
  679.     Ptr endPtr;
  680.  
  681.     theMenuHandle = (MenuHandle)NewPermHandle(GetHandleSize(CMNUHandle));
  682.     LockHandleHigh(CMNUHandle);
  683.     LockHandleHigh((Handle)theMenuHandle);
  684.  
  685.     theCMNUPtr = (Ptr)StripLong(*CMNUHandle);
  686.     theMENUPtr = (Ptr)StripLong(*theMenuHandle);
  687.     menuNo = *((IntegerPtr)theCMNUPtr);
  688.  
  689.     i = (*((Str255 *)(theCMNUPtr + 14))).Length() + 15;
  690.     BlockMove(theCMNUPtr, theMENUPtr, i);        // move menu header into MENU resource 
  691.     theCMNUPtr = (Ptr)(theCMNUPtr + i);
  692.     theMENUPtr = (Ptr)(theMENUPtr + i);
  693.     itemNo = 0;
  694.     endPtr = (Ptr)(theCMNUPtr + GetHandleSize(CMNUHandle));
  695.     while ((theCMNUPtr < endPtr) && (((*((Str255 *)theCMNUPtr)).Length()) != 0))
  696.     {
  697.         i = ((*((Str255 *)theCMNUPtr)).Length()) + 5;
  698.         BlockMove(theCMNUPtr, theMENUPtr, i);    // move menu item data sans command number 
  699.         theCMNUPtr = (Ptr)(theCMNUPtr + i);
  700.         theMENUPtr = (Ptr)(theMENUPtr + i);
  701.         if ((((long)theCMNUPtr) & 0x00000001) == 1)// word align 
  702.             theCMNUPtr = (Ptr)(theCMNUPtr + 1);
  703.         cmdNo = *((CmdNumberPtr)theCMNUPtr);
  704.         ++itemNo;
  705.         theCMNUPtr = (Ptr) (theCMNUPtr + sizeof(CmdNumber));
  706.  
  707.         gCmdTable->AddToTable(cmdNo, menuNo, itemNo);
  708.     }
  709.     (*theMENUPtr) = 0;                            // termination mark 
  710.     ++theMENUPtr;
  711.     SetPermHandleSize((Handle)theMenuHandle, (Size)(theMENUPtr - StripLong((*theMenuHandle))));
  712.  
  713.     HUnlock(CMNUHandle);
  714.     HUnlock((Handle)theMenuHandle);
  715.     return theMenuHandle;
  716. }
  717.  
  718. //--------------------------------------------------------------------------------------------------
  719.  
  720. struct JmpRec
  721. {
  722.     short opcode;
  723.     pascal void(* target)(short message,
  724.                           MenuHandle aMenuHandle,
  725.                           Rect& menuRect,
  726.                           Point hitPt,
  727.                           short& whichItem);
  728.  
  729. };
  730.  
  731.  
  732. typedef JmpRec* JmpRecPtr;
  733.  
  734. pascal void InitUMenuMgr(void)
  735.  
  736. {
  737.     short num;
  738.     MenuHandle newMenu;
  739.     Handle h;
  740.     short i;
  741.  
  742.     gCmdTable = NULL;
  743.     gMenuTable = NULL;
  744.     pHNullMenuProc = NULL;
  745.  
  746.     // Create the table 
  747.     gCmdTable = new TCmdTable;
  748.     gCmdTable->ICmdTable();
  749.  
  750.     // Create the table 
  751.     gMenuTable = new TMenuTable;
  752.     gMenuTable->IMenuTable();
  753.  
  754.     // initialize all CMNUs 
  755.     num = CountResources('CMNU');
  756.     FailResError();
  757.     for (i = 1; i <= num; ++i)
  758.     {
  759.         Handle CMNUHandle = GetIndResource('CMNU', i);
  760.         FailNILResource(CMNUHandle);
  761.         if (((* (MenuHandle) CMNUHandle)->menuID) > 0)        // not in reserved range
  762.             {
  763.             // load the menudef and store it's reference in the menu 
  764.             newMenu = ConvertToMenu(CMNUHandle);
  765.             h = GetResource('MDEF', (short)(((long)(*newMenu)->menuProc) >> sizeof(short)));
  766.             (*newMenu)->menuProc = h;
  767.     
  768.             gMenuTable->Insert((Handle) newMenu);
  769.             }
  770.     }
  771.  
  772.     // initialize all MENUs 
  773.     num = CountResources('MENU');
  774.     FailResError();
  775.     for (i = 1; i <= num; ++i)
  776.     {
  777.         newMenu = (MenuHandle)GetIndResource('MENU', i);
  778.         FailNILResource((Handle) newMenu);
  779.  
  780.         if (((*newMenu)->menuID) > 0)        // not in reserved range
  781.             {
  782.             // load the menudef and store it's reference in the menu 
  783.             h = GetResource('MDEF', (short)(((long)(*newMenu)->menuProc) >> sizeof(short)));
  784.             (*newMenu)->menuProc = h;
  785.     
  786.             gMenuTable->Insert((Handle)newMenu);
  787.             }
  788.     }
  789.  
  790.     // Create the null menu proc 
  791.     pHNullMenuProc = NewPermHandle(sizeof(JmpRec));
  792.     (*((JmpRecPtr) * pHNullMenuProc)).opcode = 0x4EF9;// JMP 
  793.     (*((JmpRecPtr) * pHNullMenuProc)).target = &NullMenuProc;
  794.  
  795. #if qDebugMsg
  796.     if (cUndo - cEditBase != kSysUndo)
  797.         fprintf(stderr, "Invalid UNDO command number");
  798.     if (cCut - cEditBase != kSysCut)
  799.         fprintf(stderr, "Invalid CUT command number");
  800.     if (cCopy - cEditBase != kSysCopy)
  801.         fprintf(stderr, "Invalid COPY command number");
  802.     if (cPaste - cEditBase != kSysPaste)
  803.         fprintf(stderr, "Invalid PASTE command number");
  804.     if (cClear - cEditBase != kSysClear)
  805.         fprintf(stderr, "Invalid CLEAR command number");
  806. #endif
  807.  
  808. }
  809.  
  810. //--------------------------------------------------------------------------------------------------
  811. #pragma segment MAMenuRes
  812.  
  813. pascal Boolean IsManagedMenu(MenuHandle theMenu)
  814.  
  815. {
  816.     return gMenuTable->GetIdentityItemNo((Handle)theMenu) != kEmptyIndex;
  817. }
  818.  
  819. //--------------------------------------------------------------------------------------------------
  820. #pragma segment MAMenuRes
  821.  
  822. pascal MenuHandle MAGetMenu(short menuNo)
  823.  
  824. {
  825.     MenuHandle theMenu = GetMHandle(menuNo);    /* do this first ... the menu is likely to be
  826.                                                   in the menubar and more likely of success,
  827.                                                   hence, faster */
  828.  
  829.     if (theMenu == NULL)                        // Try the menu list 
  830.     {
  831.         theMenu = gMenuTable->GetMenu(menuNo);
  832.  
  833.         if (theMenu == NULL)                    // darn! Try the resource chain 
  834.             theMenu = GetResMenu(menuNo);
  835.     }
  836.  
  837.     return theMenu;
  838. }
  839.  
  840. //--------------------------------------------------------------------------------------------------
  841. #pragma segment MAInit
  842.  
  843. pascal Handle MAGetNewMBar(short menuRsrcID)
  844.  
  845. {
  846.     MCTableHandle theColorTab;
  847.     Handle itsRsrcHandle;
  848.     SignedByte savedState;
  849.     Handle itsNewMBar;
  850.  
  851.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  852.         theColorTab = GetMCInfo();
  853.  
  854.     // make the 'MBAR' resource non-purgeable, so the Toolbox doesn't die 
  855.     itsRsrcHandle = GetResource('MBAR', menuRsrcID);
  856.     if (itsRsrcHandle)
  857.     {
  858.         savedState = HGetState(itsRsrcHandle);
  859.         HNoPurge(itsRsrcHandle);
  860.     }
  861.  
  862.     itsNewMBar = GetNewMBar(menuRsrcID);
  863.  
  864.     // restore the 'MBAR' resource 
  865.     if (itsRsrcHandle)
  866.         HSetState(itsRsrcHandle, savedState);
  867.  
  868.     if (theColorTab && (qNeedsColorQD || gConfiguration.hasColorQD))
  869.     {
  870.         HLock((Handle)theColorTab);
  871.         SetMCEntries((short)(GetHandleSize((Handle)theColorTab) / sizeof(MCEntry)), (*theColorTab));
  872.         HUnlock((Handle)theColorTab);
  873.         DispMCInfo(theColorTab);
  874.     }
  875.  
  876.     return itsNewMBar;
  877. }
  878.  
  879. //--------------------------------------------------------------------------------------------------
  880. #pragma segment MAMenuRes
  881.  
  882. pascal void MAInsertMenu(MenuHandle theMenu,
  883.                          short beforeID)
  884.  
  885. {
  886.     MenuCRsrcHandle theColorRsrc;
  887.  
  888.     InsertMenu(theMenu, beforeID);
  889.     /* Since only GetMenu automatically loads the appropriate color information,
  890.       and (sigh) since we can only call GetMenu once, and if you call DeleteMenu
  891.       all the good color stuff goes away (double sigh) we'll have to help out
  892.       the Menu Manager by doing its job for it */
  893.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  894.     {
  895.         theColorRsrc = (MenuCRsrcHandle)GetResource('mctb', (*theMenu)->menuID);
  896.         if (theColorRsrc)
  897.         {
  898.             HLock((Handle)theColorRsrc);
  899.             SetMCEntries((*theColorRsrc)->numEntries, &((*theColorRsrc)->mcEntryRecs[0]));
  900.             HUnlock((Handle)theColorRsrc);
  901.             ReleaseResource((Handle)theColorRsrc);
  902.         }
  903.     }
  904. }
  905.  
  906. //--------------------------------------------------------------------------------------------------
  907. #pragma segment MAMenuRes
  908.  
  909. pascal void NeedCalcMenuSize(MenuHandle aMenuHandle)
  910.  
  911. {
  912.     if ((*aMenuHandle)->menuProc == pHNullMenuProc)
  913.         (*aMenuHandle)->menuWidth = 0;
  914. }
  915.  
  916. //--------------------------------------------------------------------------------------------------
  917. #pragma segment MAMenuRes
  918. /* a null menuProc that is used to inhibit re-calculating the menu's size after each
  919.   call to EnableItem, CheckItem, etc. */
  920.  
  921. pascal void NullMenuProc(short,
  922.                          MenuHandle aMenuHandle,
  923.                          Rect& ,
  924.                          Point,
  925.                          short&)
  926.  
  927. {
  928.     (*aMenuHandle)->menuWidth = 0;
  929. }
  930.  
  931. //--------------------------------------------------------------------------------------------------
  932. #pragma segment MAMenuRes
  933.  
  934. /* If hierarchical the range of IDs for applications is restricted
  935.   See IM V-236. */
  936. #define        kHierarchicalMin    0
  937. #define        kHierarchicalMax    235
  938.  
  939. typedef Boolean EnableArray[mLastMenu];            // Saved enable flags 
  940. typedef Handle SavePrArray[mLastMenu];            // Saved menu procs 
  941.  
  942. struct SetupStruct
  943. {
  944.     EnableArray wasEnabled;
  945.     SavePrArray savedProcs;
  946. };
  947.  
  948.  
  949. typedef SetupStruct* SetupStructPtr;
  950.  
  951. Boolean IsSetupMenu(MenuHandle aMenuHandle,
  952.                     Boolean isHierarchical)
  953.  
  954. {
  955.     short menuID = (*aMenuHandle)->menuID;
  956.  
  957.     return (((menuID >= mFirstMenu) && (menuID <= mLastMenu))    // Range of managed menus
  958.             && (menuID != mApple)                                // _NEVER_ managed! 
  959.             && (!isHierarchical                                    // No further restrictions, unless…
  960.             || (isHierarchical && (menuID >= kHierarchicalMin) && (menuID <= kHierarchicalMax))));// must be in valid range for hierarchicals
  961. }
  962.  
  963.  
  964. pascal void StartMenuSetup(MenuHandle aMenuHandle,
  965.                            Boolean isHierarchical,
  966.                            void* staticLink)
  967. {
  968.     short theCmd;
  969.     short menuID = (*aMenuHandle)->menuID;
  970.  
  971.     if (IsSetupMenu(aMenuHandle, isHierarchical))
  972.     {
  973.         /* Remember the menu itself was enabled, and disable the menu
  974.           and all of its items. */
  975.         ((SetupStructPtr)staticLink)->wasEnabled[menuID] = (Boolean)((*aMenuHandle)->enableFlags & 1);
  976.         (*aMenuHandle)->enableFlags = 0;
  977.  
  978.         // Save the menu's menuproc and set it to the NullMenuProc, so that
  979.         // CalcMenuSize is disabled (will do ÇalcMenuSize at end of setup).
  980.         ((SetupStructPtr)staticLink)->savedProcs[menuID] = (*aMenuHandle)->menuProc;// See comment below 
  981.         (*aMenuHandle)->menuProc = pHNullMenuProc;
  982.  
  983.         // Uncheck all items. 
  984.         for (short item = 1; item <= CountMItems(aMenuHandle); ++item)// Make sure we don't check items with sub-menus 
  985.         {
  986.             GetItemCmd(aMenuHandle, item, theCmd);
  987.             if (theCmd != hMenuCmd)
  988.                 CheckItem(aMenuHandle, item, FALSE);// moves/purges memory 
  989.         }
  990.     }
  991. }
  992.  
  993.  
  994. pascal void EndMenuSetup(MenuHandle aMenuHandle,
  995.                          Boolean isHierarchical,
  996.                          void* staticLink)
  997.  
  998. {
  999.     long newFlags;
  1000.  
  1001.     if (IsSetupMenu(aMenuHandle, isHierarchical))
  1002.     {
  1003.         newFlags = (*aMenuHandle)->enableFlags;
  1004.         // If any items are enabled, enable the menu 
  1005.         if (newFlags != 0)
  1006.         {
  1007.             newFlags = (1 | newFlags);
  1008.             (*aMenuHandle)->enableFlags = newFlags;
  1009.         }
  1010.  
  1011.         // If the menu's enabled state changed, we have to draw the menu bar. 
  1012.         if (((newFlags & 1) == 1) != ((SetupStructPtr)staticLink)->wasEnabled[(*aMenuHandle)->menuID])
  1013.             InvalidateMenuBar();
  1014.  
  1015.         // Restore the menuproc. 
  1016.         (*aMenuHandle)->menuProc = ((SetupStructPtr)staticLink)->savedProcs[(*aMenuHandle)->menuID];
  1017.  
  1018.         /* menuWidth set to 0 by routines that require CalcMenuSize, by
  1019.           calling NeedCalcMenu. */
  1020.         if (!(*aMenuHandle)->menuWidth)
  1021.             CalcMenuSize(aMenuHandle);
  1022.     }
  1023. }
  1024.  
  1025.  
  1026. pascal void PerformMenuSetup(pascal void(* TheMenuSetterUpper)(void* staticLink),
  1027.                              void* staticLink)
  1028.  
  1029. {
  1030.     SetupStruct itsSetupStruct;
  1031.  
  1032.     EachMenuDo(&StartMenuSetup, &itsSetupStruct);
  1033.     TheMenuSetterUpper(staticLink);
  1034.     EachMenuDo(&EndMenuSetup, &itsSetupStruct);
  1035.  
  1036.     if (MenuBarHasPendingUpdate())                // Never executed on system with InvalMenuBar
  1037.     {
  1038.         DrawMenuBar();
  1039.         ValidateMenuBar();
  1040.     }
  1041.  
  1042.     ValidateMenus();
  1043. }
  1044.  
  1045. //--------------------------------------------------------------------------------------------------
  1046. #pragma segment MAMenuRes
  1047.  
  1048. pascal void SetCmdIcon(CmdNumber aCmd,
  1049.                        Byte menuIcon)
  1050.  
  1051. {
  1052.     short menu;
  1053.     short item;
  1054.     MenuHandle aMenuHandle;
  1055.  
  1056. #if qDebugMsg
  1057.     if (gTraceSetupMenus)
  1058.         fprintf(stderr, "..... SetCmdIcon(%c%d)", TraceMenuName(aCmd), menuIcon);
  1059. #endif
  1060.  
  1061.     aMenuHandle = CmdToComponents(aCmd, menu, item);
  1062.     if (aMenuHandle)
  1063.         SetItemIcon(aMenuHandle, item, menuIcon);
  1064. }
  1065.  
  1066. //--------------------------------------------------------------------------------------------------
  1067. #pragma segment MAMenuRes
  1068.  
  1069. pascal void SetCmdName(CmdNumber aCmd,
  1070.                        const Str255& menuText)
  1071.  
  1072. {
  1073.     short menu;
  1074.     short item;
  1075.     MenuHandle aMenuHandle;
  1076.  
  1077. #if qDebugMsg
  1078.     if (gTraceSetupMenus)
  1079.         fprintf(stderr, "..... SetCmdName(%c“%s”)", TraceMenuName(aCmd), (char *) menuText);
  1080. #endif
  1081.  
  1082.     aMenuHandle = CmdToComponents(aCmd, menu, item);
  1083.     if (aMenuHandle)
  1084.         SetItem(aMenuHandle, item, menuText);
  1085. }
  1086.  
  1087. //--------------------------------------------------------------------------------------------------
  1088. #pragma segment MAMenuRes
  1089.  
  1090. pascal void SetIndCmdName(CmdNumber aCmd,
  1091.                           short rsrcID,
  1092.                           short strIndex)
  1093.  
  1094. {
  1095.     Str255 s;
  1096.  
  1097.     GetIndString(s, rsrcID, strIndex);
  1098.     SetCmdName(aCmd, s);
  1099. }
  1100.  
  1101. //--------------------------------------------------------------------------------------------------
  1102. #pragma segment MAMenuRes
  1103.  
  1104. pascal void SetMenuState(CmdNumber aCmd,
  1105.                          short rsrcID,
  1106.                          short falseBuzzItem,
  1107.                          short trueBuzzItem,
  1108.                          Boolean stateVariable)
  1109.  
  1110. {
  1111.     short buzzItem;
  1112.  
  1113.     if (stateVariable)
  1114.         buzzItem = trueBuzzItem;
  1115.     else
  1116.         buzzItem = falseBuzzItem;
  1117.  
  1118.     SetIndCmdName(aCmd, rsrcID, buzzItem);
  1119. }
  1120.  
  1121. //--------------------------------------------------------------------------------------------------
  1122. #pragma segment MAMenuRes
  1123.  
  1124. pascal void SetStyle(CmdNumber aCmd, /* Style */ short aStyle)
  1125.  
  1126. {
  1127.     short menu;
  1128.     short item;
  1129.     MenuHandle aMenuHandle;
  1130.  
  1131. #if qDebugMsg
  1132.     if (gTraceSetupMenus)
  1133.         fprintf(stderr, "..... SetStyle(%c%d)", TraceMenuName(aCmd), *((Ptr) & aStyle));
  1134. #endif
  1135.  
  1136.     aMenuHandle = CmdToComponents(aCmd, menu, item);
  1137.     if (aMenuHandle)
  1138.         SetItemStyle(aMenuHandle, item, aStyle);
  1139. }
  1140.  
  1141.  
  1142.